home *** CD-ROM | disk | FTP | other *** search
/ Enter 2004 April / enter-2004-04.iso / files / httrack-3.30.exe / {app} / src / htsftp.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-10-11  |  32.8 KB  |  1,165 lines

  1. /* ------------------------------------------------------------ */
  2. /*
  3. HTTrack Website Copier, Offline Browser for Windows and Unix
  4. Copyright (C) Xavier Roche and other contributors
  5.  
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  19.  
  20.  
  21. Important notes:
  22.  
  23. - We hereby ask people using this source NOT to use it in purpose of grabbing
  24. emails addresses, or collecting any other private information on persons.
  25. This would disgrace our work, and spoil the many hours we spent on it.
  26.  
  27.  
  28. Please visit our Website: http://www.httrack.com
  29. */
  30.  
  31.  
  32. /* ------------------------------------------------------------ */
  33. /* File: basic FTP protocol manager                             */
  34. /* Author: Xavier Roche                                         */
  35. /* ------------------------------------------------------------ */
  36.  
  37. // Gestion protocole ftp
  38. // Version .05 (01/2000)
  39.  
  40. #include "htsftp.h"
  41.  
  42. #include "htsglobal.h"
  43. #include "htsbase.h"
  44. #include "htsnet.h"
  45. #include "htsthread.h"
  46. #include <stdio.h>
  47. #include <stdlib.h>
  48. #include <string.h>
  49. #if HTS_WIN
  50. #else
  51. //inet_ntoa
  52. #include <arpa/inet.h>
  53. #endif
  54.  
  55. #if HTS_WIN
  56. #ifndef __cplusplus
  57. // DOS
  58. #include <process.h>    /* _beginthread, _endthread */
  59. #endif
  60. #endif
  61.  
  62. // ftp mode passif
  63. // #if HTS_INET6==0
  64. #define FTP_PASV 1
  65. // #else
  66. // no passive mode for v6
  67. // #define FTP_PASV 0
  68. // #endif
  69.  
  70. #define FTP_DEBUG 0
  71. //#define FORK_DEBUG 0
  72.  
  73. #define FTP_STATUS_READY 1001
  74.  
  75. #if USE_BEGINTHREAD
  76. /*
  77. #ifdef __cplusplus
  78. // C++ -> Shell
  79. UINT back_launch_ftp( LPVOID pP ) {
  80.   lien_back* back=(lien_back*) pP;
  81.   if (back == NULL) {
  82.     //back->status=FTP_STATUS_READY;    // fini
  83.     //back->r.statuscode=-1;
  84.     return -1;
  85.   }
  86.   
  87.   // lancer ftp
  88.   run_launch_ftp(back);
  89.   // prΩt
  90.   back->status=0;
  91.  
  92.   return 0;    // thread completed successfully
  93. }
  94. #else
  95. */
  96. PTHREAD_TYPE back_launch_ftp( void* pP ) {
  97.   lien_back* back=(lien_back*) pP;
  98.   if (back == NULL) {
  99.     //back->status=FTP_STATUS_READY;    // fini
  100.     //back->r.statuscode=-1;
  101. #if FTP_DEBUG
  102.     printf("[ftp error: no args]\n");
  103. #endif
  104.     return PTHREAD_RETURN;
  105.   }
  106.  
  107.   /* Initialize */ 
  108.   hts_init();
  109.  
  110.   // lancer ftp
  111. #if FTP_DEBUG
  112.   printf("[Launching main ftp routine]\n");
  113. #endif
  114.   run_launch_ftp(back);
  115.   // prΩt
  116.   back->status=0;
  117.   
  118.   /* Uninitialize */
  119.   hts_uninit();
  120.   return PTHREAD_RETURN;
  121. }
  122. /*#endif*/
  123. // lancer en back
  124. void launch_ftp(lien_back* back) {
  125. /*
  126. #ifdef __cplusplus
  127.   // C++ -> Shell
  128.   AfxBeginThread(back_launch_ftp,(LPVOID) back);
  129. #else
  130. */
  131.   // DOS
  132. #if FTP_DEBUG
  133.   printf("[Launching main ftp thread]\n");
  134. #endif
  135.   _beginthread(back_launch_ftp, 0, (void*) back);
  136. /*#endif*/
  137. }
  138.  
  139. #else
  140. // Unix sans pthread
  141. int back_launch_ftp(lien_back* back) {
  142.   // lancer ftp
  143.   run_launch_ftp(back);
  144.   // prΩt
  145.   back->status=0;
  146.   return 0;
  147. }
  148. void launch_ftp(lien_back* back,char* path,char* exec) {
  149.   FILE* fp = fopen(fconv(path),"wb");
  150.   if (fp) {
  151.     char _args[8][256];
  152.     char *args[8];
  153.     fclose(fp); fp=NULL;
  154.     
  155.     strcpybuff(_args[0],exec);
  156.     strcpybuff(_args[1],"-#R");
  157.     strcpybuff(_args[2],back->url_adr);
  158.     strcpybuff(_args[3],back->url_fil);
  159.     strcpybuff(_args[4],back->url_sav);
  160.     strcpybuff(_args[5],path);
  161.     //strcpybuff(_args[6],"");
  162.     args[0]=_args[0];
  163.     args[1]=_args[1];
  164.     args[2]=_args[2];
  165.     args[3]=_args[3];
  166.     args[4]=_args[4];
  167.     args[5]=_args[5];
  168.     args[6]=NULL;
  169.     switch (fork()) {    // note: vfork dΘconne un max'
  170.     case -1: printf("Can not vfork() process\n"); break;
  171.     case 0: 
  172.       if (execvp(args[0],args)==-1) {
  173.         fp=fopen(fconv(path),"wb");
  174.         if (fp) {
  175.           fprintf(fp,"-1 unable to launch %s",args[0]);
  176.           fclose(fp); fp=NULL;
  177.           rename(path,concat(path,".ok"));
  178.         } else remove(path);
  179.       }
  180.       _exit(0);    // exit 'propre'
  181.       break;
  182.     default:  // parent
  183.       // bah on fait rien..
  184.       break;         
  185.     }
  186.   }
  187. }
  188. #endif
  189.  
  190. // pour l'arrΩt du ftp
  191. #ifdef _WIN32
  192. #define _T_SOC_close(soc)  closesocket(soc); soc=INVALID_SOCKET;
  193. #else
  194. #define _T_SOC_close(soc)  close(soc); soc=INVALID_SOCKET;
  195. #endif
  196. #define _HALT_FTP { \
  197.   if ( soc_ctl     != INVALID_SOCKET ) _T_SOC_close(soc_ctl); \
  198.   if ( soc_servdat != INVALID_SOCKET ) _T_SOC_close(soc_servdat); \
  199.   if ( soc_dat     != INVALID_SOCKET ) _T_SOC_close(soc_dat); \
  200. }
  201. #define _CHECK_HALT_FTP \
  202.   if (stop_ftp(back)) { \
  203.   _HALT_FTP \
  204.   return 0; \
  205.   }
  206.  
  207. // la vΘritable fonction une fois lancΘes les routines thread/fork
  208. int run_launch_ftp(lien_back* back) {
  209.   char user[256]="anonymous";
  210.   char pass[256]="user@";
  211.   char line_retr[2048];
  212.   int port=21;
  213. #if FTP_PASV
  214.   int port_pasv=0;
  215. #endif
  216.   char adr_ip[1024];
  217.   char *adr,*real_adr;
  218.   char* ftp_filename="";
  219.   int timeout = 300;    // timeout
  220.   int timeout_onfly=8;  // attente rΘponse supplΘmentaire
  221.   int transfer_list=0;  // directory
  222.   int rest_understood=0;  // rest command understood
  223.   t_fullhostent fullhostent_buffer;   // buffer pour resolver
  224.   //
  225.   T_SOC soc_ctl=INVALID_SOCKET;
  226.   T_SOC soc_servdat=INVALID_SOCKET;
  227.   T_SOC soc_dat=INVALID_SOCKET;
  228.   //
  229.   SOCaddr server_data;
  230.   int server_data_size=sizeof(server_data);
  231.   //
  232.   line_retr[0]=adr_ip[0]='\0';
  233.   
  234.   timeout=300;
  235.   
  236.   // effacer
  237.   strcpybuff(back->r.msg,"");
  238.   back->r.statuscode=0;
  239.   back->r.size=0;
  240.   
  241.   // rΘcupΘrer user et pass si prΘsents, et sauter user:id@ dans adr
  242.   real_adr = strchr(back->url_adr,':');
  243.   if (real_adr) real_adr++;
  244.   else real_adr=back->url_adr;
  245.   while(*real_adr=='/') real_adr++;    // sauter /
  246.   if ( (adr = jump_identification(real_adr)) != real_adr) {  // user
  247.     int i=-1;
  248.     pass[0]='\0';
  249.     do {
  250.       i++;
  251.       user[i]=real_adr[i];
  252.     } while( (real_adr[i]!=':') && (real_adr[i]) );
  253.     user[i]='\0';
  254.     if (real_adr[i]==':') {    // pass
  255.       int j=-1;
  256.       i++;  // oui on saute aussi le :
  257.       do {
  258.         j++;
  259.         pass[j]=real_adr[i+j];
  260.       } while( ((&real_adr[i+j+1]) < adr) && (real_adr[i+j]) );
  261.       pass[j]='\0';
  262.     }
  263.   }
  264.   
  265.   // Calculer RETR <nom>
  266.   {
  267.     char* a;
  268. #if 0
  269.     a=back->url_fil + strlen(back->url_fil)-1;
  270.     while( (a > back->url_fil) && (*a!='/')) a--;
  271.     if (*a != '/') {
  272.       a = NULL;
  273.     }
  274. #else
  275.     a = back->url_fil;
  276. #endif
  277.     if (a != NULL && *a != '\0') {
  278. #if 0
  279.       a++;    // sauter /
  280. #endif
  281.       ftp_filename=a;
  282.       if (strnotempty(a)) {
  283.         char* ua=unescape_http(a);
  284.         if (
  285.           (strchr(ua, ' '))
  286.           ||
  287.           (strchr(ua, '\"'))
  288.           ||
  289.           (strchr(ua, '\''))
  290.           ) {
  291.           sprintf(line_retr,"RETR \"%s\"",ua);
  292.         } else {      /* Regular one */
  293.           sprintf(line_retr,"RETR %s",ua);
  294.         }
  295.       } else {
  296.         transfer_list=1;
  297.         sprintf(line_retr,"LIST -A");
  298.       }
  299.     } else {
  300.       strcpybuff(back->r.msg,"Unexpected PORT error");
  301.       back->status=FTP_STATUS_READY;    // fini
  302.       back->r.statuscode=-1;
  303.     }
  304.   }
  305.   
  306. #if FTP_DEBUG
  307.   printf("Connecting to %s...\n",adr);
  308. #endif
  309.   
  310.   // connexion
  311.   {
  312.     SOCaddr server;
  313.     int server_size=sizeof(server);
  314.     t_hostent* hp;    
  315.     char * a;
  316.     char _adr[256];
  317.     _adr[0]='\0';
  318.     //T_SOC soc_ctl;
  319.     // effacer structure
  320.     memset(&server, 0, sizeof(server));
  321.     
  322.     // port
  323.     a=strchr(adr,':');    // port
  324.     if (a) {
  325.       sscanf(a+1,"%d",&port);
  326.       strncatbuff(_adr,adr,(int) (a - adr));
  327.     } else
  328.       strcpybuff(_adr,adr);
  329.     
  330.     // rΘcupΘrer adresse rΘsolue
  331.     strcpybuff(back->info,"host name");
  332.     hp = hts_gethostbyname(_adr, &fullhostent_buffer);
  333.     if (hp == NULL) {
  334.       strcpybuff(back->r.msg,"Unable to get server's address");
  335.       back->status=FTP_STATUS_READY;    // fini
  336.       back->r.statuscode=-5;
  337.       _HALT_FTP
  338.         return 0;
  339.     }
  340.     _CHECK_HALT_FTP;
  341.     
  342.     // copie adresse
  343.     SOCaddr_copyaddr(server, server_size, hp->h_addr_list[0], hp->h_length);
  344.     // copie adresse pour cnx data
  345.     SOCaddr_copyaddr(server_data, server_data_size, hp->h_addr_list[0], hp->h_length);
  346.     // memcpy(&server.sin_addr, hp->h_addr, hp->h_length);
  347.     
  348.     // crΘer ("attachement") une socket (point d'accΦs) internet,en flot
  349.     soc_ctl=socket(SOCaddr_sinfamily(server), SOCK_STREAM, 0);
  350.     if (soc_ctl==INVALID_SOCKET) {
  351.       strcpybuff(back->r.msg,"Unable to create a socket");
  352.       back->status=FTP_STATUS_READY;    // fini
  353.       back->r.statuscode=-1;
  354.       _HALT_FTP
  355.         return 0;
  356.     }
  357.  
  358.     SOCaddr_initport(server, port);
  359.     // server.sin_port = htons((unsigned short int) port);
  360.     
  361.     // connexion (bloquante, on est en thread)
  362.     strcpybuff(back->info,"connect");
  363.  
  364. #if HTS_WIN
  365.     if (connect(soc_ctl, (const struct sockaddr FAR *)&server, server_size) != 0) {
  366. #else
  367.       if (connect(soc_ctl, (struct sockaddr *)&server, server_size) == -1) {
  368. #endif
  369.         strcpybuff(back->r.msg,"Unable to connect to the server");
  370.         back->status=FTP_STATUS_READY;    // fini
  371.         back->r.statuscode=-1;
  372.         _HALT_FTP
  373.           return 0;
  374. #if HTS_WIN
  375.       }
  376. #else
  377.     }
  378. #endif
  379.     _CHECK_HALT_FTP;
  380.     
  381.     {
  382.       char line[1024];
  383.       // envoi du login
  384.       
  385.       // --USER--
  386.       get_ftp_line(soc_ctl,line,timeout);    // en tΩte
  387.       _CHECK_HALT_FTP;
  388.       
  389.       if (line[0]=='2') {        // ok, connectΘ
  390.         strcpybuff(back->info,"login: user");
  391.         sprintf(line,"USER %s",user);
  392.         send_line(soc_ctl,line);
  393.         get_ftp_line(soc_ctl,line,timeout);
  394.         _CHECK_HALT_FTP;      
  395.         if ((line[0]=='3') || (line[0]=='2')) {
  396.           // --PASS--
  397.           strcpybuff(back->info,"login: pass");
  398.           sprintf(line,"PASS %s",pass);
  399.           send_line(soc_ctl,line);
  400.           get_ftp_line(soc_ctl,line,timeout);
  401.           _CHECK_HALT_FTP;      
  402.           if (line[0]=='2') {  // ok
  403. #if 0
  404.             // --CWD--
  405.             char* a;
  406.             a=back->url_fil + strlen(back->url_fil)-1;
  407.             while( (a > back->url_fil) && (*a!='/')) a--;
  408.             if (*a == '/') {    // ok repΘrΘ
  409.               char target[1024];
  410.               target[0]='\0';
  411.               strncatbuff(target,back->url_fil,(int) (a - back->url_fil));
  412.               if (strnotempty(target)==0)
  413.                 strcatbuff(target,"/");
  414.               strcpybuff(back->info,"cwd");
  415.               sprintf(line,"CWD %s",target);
  416.               send_line(soc_ctl,line);
  417.               get_ftp_line(soc_ctl,line,timeout);
  418.               _CHECK_HALT_FTP;      
  419.               if (line[0]=='2') {
  420.                 send_line(soc_ctl,"TYPE I");
  421.                 get_ftp_line(soc_ctl,line,timeout);
  422.                 _CHECK_HALT_FTP;      
  423.                 if (line[0]=='2') {
  424.                   // ok..
  425.                 } else {
  426.                   strcpybuff(back->r.msg,"TYPE I error");
  427.                   back->status=FTP_STATUS_READY;    // fini
  428.                   back->r.statuscode=-1;
  429.                 }
  430.               } else {
  431.                 sprintf(back->r.msg,"CWD error: %s",linejmp(line));
  432.                 back->status=FTP_STATUS_READY;    // fini
  433.                 back->r.statuscode=-1;
  434.               }    // sinon on est prΩts
  435.             } else {
  436.               strcpybuff(back->r.msg,"Unexpected ftp error");
  437.               back->status=FTP_STATUS_READY;    // fini
  438.               back->r.statuscode=-1;
  439.             }
  440. #endif
  441.             
  442.           } else {
  443.             sprintf(back->r.msg,"Bad password: %s",linejmp(line));
  444.             back->status=FTP_STATUS_READY;    // fini
  445.             back->r.statuscode=-1;
  446.           }
  447.         } else {
  448.           sprintf(back->r.msg,"Bad user name: %s",linejmp(line));
  449.           back->status=FTP_STATUS_READY;    // fini
  450.           back->r.statuscode=-1;
  451.         }
  452.       } else {
  453.         sprintf(back->r.msg,"Connection refused: %s",linejmp(line));
  454.         back->status=FTP_STATUS_READY;    // fini
  455.         back->r.statuscode=-1;
  456.       }
  457.      
  458.       // ok, si on est prΩts on Θcoute sur un port et on demande la sauce
  459.       if (back->r.statuscode != -1) {
  460.  
  461.         
  462.         //
  463.         // PrΘ-REST
  464.         //
  465. #if FTP_PASV
  466.         if (SOCaddr_getproto(server, server_size) == '1') {
  467.           strcpybuff(back->info,"pasv");
  468.           sprintf(line,"PASV");
  469.           send_line(soc_ctl,line);
  470.           get_ftp_line(soc_ctl,line,timeout);
  471.         } else { /* ipv6 */
  472.           line[0]='\0';
  473.         }
  474.         _CHECK_HALT_FTP;      
  475.         if (line[0]=='2') {
  476.           char *a,*b,*c;
  477.           a=strchr(line,'(');       // exemple: 227 Entering Passive Mode (123,45,67,89,177,27)
  478.           if (a) {
  479.            
  480.             // -- analyse de l'adresse IP et du port --
  481.             a++;
  482.             b=strchr(a,',');
  483.             if (b) b=strchr(b+1,',');
  484.             if (b) b=strchr(b+1,',');
  485.             if (b) b=strchr(b+1,',');
  486.             c=a; while( (c=strchr(c,',')) ) *c='.';        // remplacer , par .
  487.             if (b) *b='\0';
  488.             //
  489.             strcpybuff(adr_ip,a);       // copier adresse ip
  490.             //
  491.             if (b) {
  492.               a=b+1;  // dΘbut du port
  493.               b=strchr(a,'.');
  494.               if (b) {
  495.                 int n1,n2;
  496.                 //
  497.                 *b='\0';
  498.                 b++;
  499.                 c=strchr(b,')');
  500.                 if (c) {
  501.                   *c='\0';
  502.                   if ( (sscanf(a,"%d",&n1)==1) && (sscanf(b,"%d",&n2)==1) && (strlen(adr_ip)<=16)) {
  503.                     port_pasv=n2+(n1<<8);
  504.                   }
  505.                 } else {
  506.                   deletesoc(soc_dat); soc_dat=INVALID_SOCKET;
  507.                 }    // sinon on est prΩts
  508.               }
  509.             }
  510.             // -- fin analyse de l'adresse IP et du port --
  511.           } else {
  512.             sprintf(back->r.msg,"PASV incorrect: %s",linejmp(line));
  513.             back->status=FTP_STATUS_READY;    // fini
  514.             back->r.statuscode=-1;
  515.           }    // sinon on est prΩts
  516.         } else {
  517.           /*
  518.             * try epsv (ipv6) *
  519.           */
  520.           strcpybuff(back->info,"pasv");
  521.           sprintf(line,"EPSV");
  522.           send_line(soc_ctl,line);
  523.           get_ftp_line(soc_ctl,line,timeout);
  524.           _CHECK_HALT_FTP;      
  525.           if (line[0]=='2') { /* got it */
  526.             char *a;
  527.             a=strchr(line,'(');       // exemple: 229 Entering Extended Passive Mode (|||6446|)
  528.             if (
  529.               (a != NULL)
  530.               &&
  531.               (*a == '(') 
  532.               && (*(a+1))
  533.               && (*(a+1) == *(a+2)) && (*(a+1) == *(a+3))
  534.               && (isdigit(*(a+4)))
  535.               && (*(a+5))
  536.               ) {
  537.               unsigned int n1 = 0;
  538.               if (sscanf(a+4,"%d",&n1)==1) {
  539.                 if ((n1 < 65535) && (n1 > 0)) {
  540.                   port_pasv=n1;
  541.                 }
  542.               }
  543.             } else {
  544.               sprintf(back->r.msg,"EPSV incorrect: %s",linejmp(line));
  545.               back->status=FTP_STATUS_READY;    // fini
  546.               back->r.statuscode=-1;
  547.             }
  548.           } else {
  549.             sprintf(back->r.msg,"PASV/EPSV error: %s",linejmp(line));
  550.             back->status=FTP_STATUS_READY;    // fini
  551.             back->r.statuscode=-1;
  552.           }    // sinon on est prΩts
  553.         }
  554. #else
  555.         // rien α faire avant
  556. #endif
  557.           
  558. #if FTP_PASV
  559.         if (port_pasv) {
  560. #endif
  561.           // SIZE
  562.           if (back->r.statuscode != -1) {
  563.             if (!transfer_list) {
  564.               char* ua=unescape_http(ftp_filename);
  565.               if (
  566.                 (strchr(ua, ' '))
  567.                 ||
  568.                 (strchr(ua, '\"'))
  569.                 ||
  570.                 (strchr(ua, '\''))
  571.                 ) {
  572.                 sprintf(line,"SIZE \"%s\"", ua);
  573.               } else {
  574.                 sprintf(line,"SIZE %s", ua);
  575.               }
  576.               
  577.               // SIZE?
  578.               strcpybuff(back->info,"size");
  579.               send_line(soc_ctl,line);
  580.               get_ftp_line(soc_ctl,line,timeout);
  581.               _CHECK_HALT_FTP;      
  582.               if (line[0]=='2') {  // SIZE compris, ALORS tester REST (sinon pas tester: cf probleme des txt.gz decompresses a la volee)
  583.                 char* szstr = strchr(line, ' ');
  584.                 if (szstr) {
  585.                   LLint size = 0;
  586.                   szstr++;
  587.                   if (sscanf(szstr, LLintP, &size) == 1) {
  588.                     back->r.totalsize = size;
  589.                   }
  590.                 }
  591.  
  592.                 // REST?
  593.                 if (fexist(back->url_sav) && (transfer_list==0)) {
  594.                   strcpybuff(back->info,"rest");
  595.                   sprintf(line,"REST "LLintP,(LLint)fsize(back->url_sav));
  596.                   send_line(soc_ctl,line);
  597.                   get_ftp_line(soc_ctl,line,timeout);
  598.                   _CHECK_HALT_FTP;      
  599.                   if ((line[0]=='3') || (line[0]=='2')) {  // ok
  600.                     rest_understood=1;
  601.                   } // sinon tant pis 
  602.                 } 
  603.               }  // sinon tant pis 
  604.             }
  605.           }
  606. #if FTP_PASV
  607.         }
  608. #endif
  609.  
  610.         //
  611.         // Post-REST
  612.         //
  613. #if FTP_PASV
  614.         // Ok, se connecter
  615.         if (port_pasv) {
  616.           SOCaddr server;
  617.           int server_size=sizeof(server);
  618.           t_hostent* hp;    
  619.           // effacer structure
  620.           memset(&server, 0, sizeof(server));
  621.           
  622.           // infos
  623.           strcpybuff(back->info,"resolv");
  624.           
  625.           // rΘsoudre
  626.           if (adr_ip[0]) {
  627.             hp = hts_gethostbyname(adr_ip, &fullhostent_buffer);
  628.             if (hp) {
  629.               SOCaddr_copyaddr(server, server_size, hp->h_addr_list[0], hp->h_length);
  630.             } else {
  631.               server_size=0;
  632.             }
  633.           } else {
  634.             memcpy(&server, &server_data, sizeof(server_data));
  635.             server_size=server_data_size;
  636.           }
  637.           
  638.           // infos
  639.           strcpybuff(back->info,"cnxdata");
  640. #if FTP_DEBUG
  641.           printf("Data: Connecting to %s:%d...\n", adr_ip, port_pasv);
  642. #endif
  643.           if (server_size > 0) {
  644.             // socket
  645.             soc_dat=socket(SOCaddr_sinfamily(server), SOCK_STREAM, 0);
  646.             if (soc_dat != INVALID_SOCKET) {
  647.               // structure: connexion au domaine internet, port 80 (ou autre)
  648.               SOCaddr_initport(server, port_pasv);
  649.               // server.sin_port = htons((unsigned short int) port_pasv);
  650. #if HTS_WIN
  651.               if (connect(soc_dat, (const struct sockaddr FAR *)&server, server_size) == 0) {
  652. #else
  653.               if (connect(soc_dat, (struct sockaddr *)&server, server_size) != -1) {
  654. #endif
  655.                 strcpybuff(back->info,"retr");
  656.                 strcpybuff(line,line_retr);
  657.                 send_line(soc_ctl,line);
  658.                 get_ftp_line(soc_ctl,line,timeout);
  659.                 _CHECK_HALT_FTP;      
  660.                 if (line[0]=='1') {
  661.                   // OK
  662.                 } else {
  663.                   deletesoc(soc_dat); soc_dat=INVALID_SOCKET;
  664.                   //
  665.                   sprintf(back->r.msg,"RETR command errror: %s",linejmp(line));
  666.                   back->status=FTP_STATUS_READY;    // fini
  667.                   back->r.statuscode=-1;
  668.                 }    // sinon on est prΩts
  669.               } else {
  670. #if FTP_DEBUG
  671.                 printf("Data: unable to connect\n");
  672. #endif
  673.                 deletesoc(soc_dat); soc_dat=INVALID_SOCKET;
  674.                 //
  675.                 strcpybuff(back->r.msg,"Unable to connect");
  676.                 back->status=FTP_STATUS_READY;    // fini
  677.                 back->r.statuscode=-1;
  678.               }    // sinon on est prΩts
  679.             } else {
  680.               strcpybuff(back->r.msg,"Unable to create a socket");
  681.               back->status=FTP_STATUS_READY;    // fini
  682.               back->r.statuscode=-1;
  683.             }    // sinon on est prΩts
  684.           } else {
  685.             sprintf(back->r.msg,"Unable to resolve IP %s",adr_ip);
  686.             back->status=FTP_STATUS_READY;    // fini
  687.             back->r.statuscode=-1;
  688.           }    // sinon on est prΩts
  689.         } else {
  690.           sprintf(back->r.msg,"PASV incorrect: %s",linejmp(line));
  691.           back->status=FTP_STATUS_READY;    // fini
  692.           back->r.statuscode=-1;
  693.         }    // sinon on est prΩts
  694. #else
  695.         //T_SOC soc_servdat;
  696.         strcpybuff(back->info,"listening");
  697.         if ( (soc_servdat = get_datasocket(line)) != INVALID_SOCKET) {
  698.           _CHECK_HALT_FTP;      
  699.           send_line(soc_ctl,line);          // envoi du RETR
  700.           get_ftp_line(soc_ctl,line,timeout);
  701.           _CHECK_HALT_FTP;      
  702.           if (line[0]=='2') {  // ok
  703.             strcpybuff(back->info,"retr");
  704.             strcpybuff(line,line_retr);
  705.             send_line(soc_ctl,line);
  706.             get_ftp_line(soc_ctl,line,timeout);
  707.             _CHECK_HALT_FTP;      
  708.             if (line[0]=='1') {
  709.               //T_SOC soc_dat;
  710.               struct sockaddr dummyaddr;
  711.               int dummylen = sizeof(struct sockaddr);
  712.               if ( (soc_dat=accept(soc_servdat,&dummyaddr,&dummylen)) == INVALID_SOCKET) {
  713.                 strcpybuff(back->r.msg,"Unable to accept connection");
  714.                 back->status=FTP_STATUS_READY;    // fini
  715.                 back->r.statuscode=-1;
  716.               }
  717.             } else {
  718.               sprintf(back->r.msg,"RETR command errror: %s",linejmp(line));
  719.               back->status=FTP_STATUS_READY;    // fini
  720.               back->r.statuscode=-1;
  721.             }
  722.           } else {
  723.             sprintf(back->r.msg,"PORT command error: %s",linejmp(line));
  724.             back->status=FTP_STATUS_READY;    // fini
  725.             back->r.statuscode=-1;
  726.           }
  727. #if HTS_WIN
  728.           closesocket(soc_servdat);
  729. #else
  730.           close(soc_servdat);
  731. #endif
  732.         } else {
  733.           strcpybuff(back->r.msg,"Unable to listen to a port");
  734.           back->status=FTP_STATUS_READY;    // fini
  735.           back->r.statuscode=-1;
  736.         }
  737. #endif
  738.         
  739.         //
  740.         // Ok, connexion initiΘe
  741.         //
  742.         if (soc_dat != INVALID_SOCKET) {
  743.           if (rest_understood) {         // REST envoyΘe et comprise
  744.             filenote(back->url_sav,NULL);
  745.             back->r.fp = fopen(fconv(back->url_sav),"ab");
  746.           } else
  747.             back->r.fp = filecreate(back->url_sav);
  748.           strcpybuff(back->info,"receiving");
  749.           if (back->r.fp != NULL) {
  750.             char buff[1024];
  751.             int len=1;
  752.             int read_len=1024;
  753.             //HTS_TOTAL_RECV_CHECK(read_len);         // Diminuer au besoin si trop de donnΘes reτues
  754.             
  755.             while( (len>0) && (!stop_ftp(back)) ) {
  756.               // attendre les donnΘes
  757.               len=1;    // pas d'erreur pour le moment
  758.               switch(wait_socket_receive(soc_dat,timeout)) {
  759.               case -1:
  760.                 strcpybuff(back->r.msg,"FTP read error");
  761.                 back->status=FTP_STATUS_READY;    // fini
  762.                 back->r.statuscode=-1;
  763.                 len=0;    // fin
  764.                 break;
  765.               case 0:
  766.                 sprintf(back->r.msg,"Time out (%d)",timeout);
  767.                 back->status=FTP_STATUS_READY;    // fini
  768.                 back->r.statuscode=-1;
  769.                 len=0;    // fin
  770.                 break;
  771.               }
  772.               
  773.               // rΘception
  774.               if (len) {
  775.                 len=recv(soc_dat,buff,read_len,0);
  776.                 if (len>0) {
  777.                   back->r.size+=len;
  778.                   HTS_STAT.HTS_TOTAL_RECV+=len; 
  779.                   if (back->r.fp) {
  780.                     if ((INTsys)fwrite(buff,1,(INTsys)len,back->r.fp) != len) {
  781.                       /*
  782.                       int fcheck;
  783.                       if ((fcheck=check_fatal_io_errno())) {
  784.                         opt->state.exit_xh=-1;
  785.                       }
  786.                       */
  787.                       strcpybuff(back->r.msg,"Write error");
  788.                       back->status=FTP_STATUS_READY;    // fini
  789.                       back->r.statuscode=-1;
  790.                       len=0;  // error
  791.                     }
  792.                   } else {
  793.                     strcpybuff(back->r.msg,"Unexpected write error");
  794.                     back->status=FTP_STATUS_READY;    // fini
  795.                     back->r.statuscode=-1;
  796.                   }
  797.                 } else {        // Erreur ou terminΘ
  798.                   back->status=FTP_STATUS_READY;    // fini
  799.                   back->r.statuscode=0;
  800.                   if (back->r.totalsize > 0 && back->r.size != back->r.totalsize) {
  801.                     back->r.statuscode=-1;
  802.                     strcpybuff(back->r.msg,"FTP file incomplete");
  803.                   }
  804.                 }
  805.                 read_len=1024; 
  806.                 //HTS_TOTAL_RECV_CHECK(read_len);         // Diminuer au besoin si trop de donnΘes reτues
  807.               }
  808.             }
  809.             if (back->r.fp) { 
  810.               fclose(back->r.fp); 
  811.               back->r.fp=NULL;
  812.             }
  813.           } else {
  814.             strcpybuff(back->r.msg,"Unable to write file");
  815.             back->status=FTP_STATUS_READY;    // fini
  816.             back->r.statuscode=-1;
  817.           }
  818. #if HTS_WIN
  819.           closesocket(soc_dat);
  820. #else
  821.           close(soc_dat);
  822. #endif
  823.           
  824.           // 226 Transfer complete?
  825.           if (back->r.statuscode != -1) {
  826.             if (wait_socket_receive(soc_ctl,timeout_onfly)>0) {
  827.               // rΘcupΘrer 226 transfer complete
  828.               get_ftp_line(soc_ctl,line,timeout);
  829.               if (line[0]=='2') {       // OK
  830.                 strcpybuff(back->r.msg,"OK");
  831.                 back->status=FTP_STATUS_READY;    // fini
  832.                 back->r.statuscode=200;
  833.               } else {
  834.                 sprintf(back->r.msg,"RETR incorrect: %s",linejmp(line));
  835.                 back->status=FTP_STATUS_READY;    // fini
  836.                 back->r.statuscode=-1;
  837.               }
  838.             } else {
  839.               strcpybuff(back->r.msg,"FTP read error");
  840.               back->status=FTP_STATUS_READY;    // fini
  841.               back->r.statuscode=-1;
  842.             }
  843.           }
  844.           
  845.         }
  846.         
  847.         
  848.         
  849.       }
  850.       
  851.       
  852.     }
  853.     
  854.     _CHECK_HALT_FTP;
  855.     strcpybuff(back->info,"quit");
  856.     send_line(soc_ctl,"QUIT");    // bye bye
  857.     get_ftp_line(soc_ctl,NULL,timeout);
  858. #if HTS_WIN
  859.     closesocket(soc_ctl);
  860. #else
  861.     close(soc_ctl);
  862. #endif
  863.   }
  864.   
  865.   if (back->r.statuscode!=-1) {
  866.     back->r.statuscode=200;
  867.     strcpybuff(back->r.msg,"OK");
  868.   }
  869.   back->status=FTP_STATUS_READY;    // fini
  870.   return 0;
  871. }
  872.  
  873.  
  874.  
  875. // ouverture d'un port
  876. T_SOC get_datasocket(char* to_send) {
  877.   T_SOC soc = INVALID_SOCKET;
  878.   char h_loc[256+2];
  879.   
  880.   to_send[0]='\0';
  881.   if (gethostname(h_loc,256)==0) {    // host name
  882.     SOCaddr server;
  883.     int server_size=sizeof(server);
  884.     t_hostent* hp_loc;
  885.     t_fullhostent buffer;
  886.  
  887.     // effacer structure
  888.     memset(&server, 0, sizeof(server));
  889.  
  890.     if ( (hp_loc=vxgethostbyname(h_loc, &buffer)) ) {  // notre host
  891.  
  892.       // copie adresse
  893.       SOCaddr_copyaddr(server, server_size, hp_loc->h_addr_list[0], hp_loc->h_length);
  894.  
  895.       if ( (soc=socket(SOCaddr_sinfamily(server), SOCK_STREAM, 0)) != INVALID_SOCKET) {
  896.  
  897.         if ( bind(soc,(struct sockaddr*) &server, server_size) == 0 ) {
  898.           SOCaddr server2;
  899.           int len;
  900.           len=sizeof(server2);
  901.           // effacer structure
  902.           memset(&server2, 0, sizeof(server2));
  903.           if (getsockname(soc,(struct sockaddr*) &server2, &len) == 0) {
  904.             // *port=ntohs(server.sin_port);  // rΘcupΘrer port
  905.             if (listen(soc,10)>=0) {    // au pif le 10
  906. #if HTS_INET6==0
  907.               unsigned short int a,n1,n2;
  908.               // calculer port
  909.               a  = SOCaddr_sinport(server2);
  910.               n1 = (a & 0xff);
  911.               n2 = ((a>>8) & 0xff);
  912.               {
  913.                 char dots[256+2];
  914.                 char dot[256+2];
  915.                 char* a;
  916.                 SOCaddr_inetntoa(dot, 256, server2, sizeof(server2));
  917.                 //
  918.                 dots[0]='\0';
  919.                 strncatbuff(dots, dot, 128);
  920.                 while( (a=strchr(dots,'.')) ) *a=',';    // virgules!
  921.                 while( (a=strchr(dots,':')) ) *a=',';    // virgules!
  922.                 sprintf(to_send,"PORT %s,%d,%d",dots,n1,n2);  
  923.               }
  924. #else
  925.               /*
  926.                 EPRT |1|132.235.1.2|6275|
  927.                 EPRT |2|1080::8:800:200C:417A|5282|
  928.               */
  929.               {
  930.                 char dot[256+2];
  931.                 SOCaddr_inetntoa(dot, 256, server2, len);
  932.                 sprintf(to_send,"EPRT |%c|%s|%d|", SOCaddr_getproto(server2, len), dot, SOCaddr_sinport(server2));  
  933.               }
  934. #endif
  935.               
  936.             } else {
  937. #if HTS_WIN
  938.               closesocket(soc);
  939. #else
  940.               close(soc);
  941. #endif
  942.               soc=INVALID_SOCKET;
  943.             }
  944.             
  945.             
  946.           } else {
  947. #if HTS_WIN
  948.             closesocket(soc);
  949. #else
  950.             close(soc);
  951. #endif
  952.             soc=INVALID_SOCKET;
  953.           }
  954.           
  955.           
  956.         } else {
  957. #if HTS_WIN
  958.           closesocket(soc);
  959. #else
  960.           close(soc);
  961. #endif
  962.           soc=INVALID_SOCKET;
  963.         }
  964.       }
  965.     }
  966.   }
  967.   
  968.   
  969.   return soc;
  970. }
  971.  
  972. #if FTP_DEBUG
  973. FILE* dd=NULL;
  974. #endif
  975.  
  976. // routines de rΘception/Θmission
  977. // 0 = ERROR
  978. int send_line(T_SOC soc,char* data) {
  979.   char line[1024];
  980.   if (_DEBUG_HEAD) {
  981.     if (ioinfo) {
  982.       fprintf(ioinfo,"---> %s\x0d\x0a",data);
  983.       fflush(ioinfo);
  984.     }
  985.   }
  986. #if FTP_DEBUG
  987.   if (dd == NULL) dd = fopen("toto.txt","w");
  988.   fprintf(dd,"---> %s\x0d\x0a",data); fflush(dd);
  989.   printf("---> %s",data); fflush(stdout);
  990. #endif
  991.   sprintf(line,"%s\x0d\x0a",data);
  992.   if (check_socket_connect(soc) != 1) {
  993. #if FTP_DEBUG
  994.     printf("!SOC WRITE ERROR\n");
  995. #endif
  996.     return 0;    // erreur, plus connectΘ!
  997.   }
  998. #if FTP_DEBUG
  999.   {
  1000.     int r = (send(soc,line,strlen(line),0) == (int) strlen(line));
  1001.     printf("%s\x0d\x0a",data); fflush(stdout);
  1002.     return r;
  1003.   }
  1004. #else
  1005.   return (send(soc,line,strlen(line),0) == (int) strlen(line));
  1006. #endif
  1007. }
  1008.  
  1009. int get_ftp_line(T_SOC soc,char* line,int timeout) {
  1010.   char data[1024];
  1011.   int i,ok,multiline;
  1012. #if FTP_DEBUG
  1013.   if (dd == NULL) dd = fopen("toto.txt","w");
  1014. #endif
  1015.   
  1016.   data[0]='\0';
  1017.   i=ok=multiline=0; data[3]='\0';
  1018.   do {
  1019.     char b;                        
  1020.     
  1021.     // vΘrifier donnΘes
  1022.     switch(wait_socket_receive(soc,timeout)) {
  1023.     case -1:   // erreur de lecture
  1024.       if (line) strcpybuff(line,"500 *read error");
  1025.       return 0;
  1026.       break;
  1027.     case 0:
  1028.       if (line) sprintf(line,"500 *read timeout (%d)",timeout);
  1029.       return 0;
  1030.       break;
  1031.     }
  1032.     
  1033.     //HTS_TOTAL_RECV_CHECK(dummy);     // Diminuer au besoin si trop de donnΘes reτues
  1034.     switch(recv(soc,&b,1,0)) {
  1035.       //case 0: break;    // pas encore --> erreur (on attend)!
  1036.     case 1:
  1037.       HTS_STAT.HTS_TOTAL_RECV+=1; // compter flux entrant
  1038.       if ((b!=10) && (b!=13))
  1039.         data[i++]=b;
  1040.       break;
  1041.     default:
  1042.       if (line) strcpybuff(line,"500 *read error");
  1043.       return 0; // error
  1044.       break;
  1045.     }
  1046.     if ( ((b==13) || (b==10)) && (i>0) ){    // CR/LF
  1047.       if (
  1048.         (data[3] == '-')
  1049.         ||
  1050.         ((multiline) && (!isdigit((unsigned char)data[0]))) 
  1051.         )
  1052.       {
  1053.         data[3]='\0';
  1054.         i=0;
  1055.         multiline=1;
  1056.       }
  1057.       else
  1058.         ok=1;    // sortir
  1059.     }
  1060.   } while(!ok);
  1061.   data[i++]='\0';
  1062.   
  1063.   if (_DEBUG_HEAD) {
  1064.     if (ioinfo) {
  1065.       fprintf(ioinfo,"<--- %s\x0d\x0a",data);
  1066.       fflush(ioinfo);
  1067.     }
  1068.   }
  1069. #if FTP_DEBUG
  1070.   fprintf(dd,"<--- %s\n",data); fflush(dd);
  1071.   printf("<--- %s\n",data);
  1072. #endif
  1073.   if (line) strcpybuff(line,data);
  1074.   return (strnotempty(data));
  1075. }
  1076.  
  1077. // sauter NNN
  1078. char* linejmp(char* line) {
  1079.   if (strlen(line)>4)
  1080.     return line+4;
  1081.   else
  1082.     return line;
  1083. }
  1084.  
  1085. // test socket:
  1086. // 0 : no data
  1087. // 1 : data detected
  1088. // -1: error
  1089. int check_socket(T_SOC soc) {
  1090.   fd_set fds,fds_e;           // poll structures
  1091.   struct timeval tv;          // structure for select
  1092.   FD_ZERO(&fds);
  1093.   FD_ZERO(&fds_e); 
  1094.   // socket read 
  1095.   FD_SET(soc,&fds);           
  1096.   // socket error
  1097.   FD_SET(soc,&fds_e);
  1098.   tv.tv_sec=0;
  1099.   tv.tv_usec=0;
  1100.   // poll!     
  1101.   select(soc + 1,&fds,NULL,&fds_e,&tv);
  1102.   if (FD_ISSET(soc,&fds_e)) {  // error detected
  1103.     return -1;
  1104.   } else if (FD_ISSET(soc,&fds)) {
  1105.     return 1;
  1106.   }
  1107.   return 0;
  1108. }
  1109. // check if connected
  1110. int check_socket_connect(T_SOC soc) {
  1111.   fd_set fds,fds_e;           // poll structures
  1112.   struct timeval tv;          // structure for select
  1113.   FD_ZERO(&fds);
  1114.   FD_ZERO(&fds_e); 
  1115.   // socket write 
  1116.   FD_SET(soc,&fds);           
  1117.   // socket error
  1118.   FD_SET(soc,&fds_e);
  1119.   tv.tv_sec=0;
  1120.   tv.tv_usec=0;
  1121.   // poll!     
  1122.   select(soc + 1,NULL,&fds,&fds_e,&tv);
  1123.   if (FD_ISSET(soc,&fds_e)) {  // error detected
  1124.     return -1;
  1125.   } else if (FD_ISSET(soc,&fds)) {
  1126.     return 1;
  1127.   }
  1128.   return 0;
  1129. }
  1130. // attendre des donnΘes
  1131. int wait_socket_receive(T_SOC soc,int timeout) {
  1132.   // attendre les donnΘes
  1133.   TStamp ltime=time_local();
  1134.   int r;
  1135. #if FTP_DEBUG
  1136.   printf("\x0dWaiting for data "); fflush(stdout);
  1137. #endif
  1138.   while( (!(r = check_socket(soc))) && ( ((int) ((TStamp) (time_local()-ltime))) < timeout )) {
  1139.     Sleep(100);
  1140. #if FTP_DEBUG
  1141.     printf("."); fflush(stdout);
  1142. #endif
  1143.   }
  1144. #if FTP_DEBUG
  1145.   printf("\x0dreturn: %d\x0d",r); fflush(stdout);
  1146. #endif
  1147.   return r;
  1148. }
  1149.  
  1150.  
  1151. // cancel reτu?
  1152. int stop_ftp(lien_back* back) {
  1153.   if (back->stop_ftp) {
  1154.     strcpybuff(back->r.msg,"Cancelled by User");
  1155.     back->status=FTP_STATUS_READY;    // fini
  1156.     back->r.statuscode=-1;
  1157.     return 1;
  1158.   }
  1159.   return 0;
  1160. }
  1161.  
  1162.  
  1163.  
  1164.  
  1165.